﻿//
// Copyright (c) 2010-2011 Jeff Wilcox
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

#if DEBUG
//#define DEBUG_CCC
#endif

using System;
using System.Diagnostics;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;

namespace WindowsPhoneEssentials.Controls
{
    public class CoverContentControl : BaseCoverContentControl
    {
        private const string ContentTemplatePart = "Content";

        #region public bool ReleaseContentTree
        /// <summary>
        /// Gets or sets a value indicating whether to release the content's visual
        /// tree when the Cover goes back up.
        /// </summary>
        public bool ReleaseContentTree
        {
            get { return (bool)GetValue(ReleaseContentTreeProperty); }
            set { SetValue(ReleaseContentTreeProperty, value); }
        }

        /// <summary>
        /// Identifies the ReleaseContentTree dependency property.
        /// </summary>
        public static readonly DependencyProperty ReleaseContentTreeProperty =
            DependencyProperty.Register(
                "ReleaseContentTree",
                typeof(bool),
                typeof(CoverContentControl),
                new PropertyMetadata(false));
        #endregion public bool ReleaseContentTree

        public event EventHandler ContentPresenterLoaded;
        public event EventHandler ContentPresenterUnloaded;

        private Panel contentPanel;
        private VisualStateGroup coveringStateGroup;

        private bool hasContentLoaded;

        public CoverContentControl()
        {
            DefaultStyleKey = typeof(CoverContentControl);
        }

        protected ContentPresenter ContentPresenter { get; private set; }

        public override void OnApplyTemplate()
        {
            if (coveringStateGroup != null)
            {
                coveringStateGroup.CurrentStateChanging -= OnCoveringStateChanging;
                coveringStateGroup.CurrentStateChanged -= OnCoveringStateChanged;
            }

            contentPanel = GetTemplateChild(ContentTemplatePart) as Panel;

            coveringStateGroup = VisualStates.TryGetVisualStateGroup(this, CoverStateGroupName);
            if (coveringStateGroup != null)
            {
                coveringStateGroup.CurrentStateChanged += OnCoveringStateChanged;
                coveringStateGroup.CurrentStateChanging += OnCoveringStateChanging;
            }

            base.OnApplyTemplate(); // Not kosher but ...
            //UpdateVisualStates(false);
        }

        public virtual bool HasContentLoaded
        {
            get
            {
                return hasContentLoaded;
            }
        }

        private void OnCoveringStateChanging(object sender, VisualStateChangedEventArgs e)
        {
            Debug("OnCoveringStateChanging");

            if (e.NewState != null && e.NewState.Name == UncoveredStateName && contentPanel != null && contentPanel.Children.Count == 0)
            {
                RealizeContent();
            }
        }

        public void RealizeContent()
        {
            if (ContentPresenter != null)
            {
                return;
                // throw new InvalidOperationException("Already realized!"); // probably want to not throw in the future, but just no-op out?
            }

            Debug("RealizeContent");

            ContentPresenter = new ContentPresenter
            {
                HorizontalAlignment = HorizontalContentAlignment,
                VerticalAlignment = VerticalContentAlignment,
                Margin = Padding,
                IsHitTestVisible = false,
            };

            ContentPresenter.Loaded += OnContentPresenterLoaded;
            ContentPresenter.Unloaded += OnContentPresenterUnloaded;

            ContentPresenter.SetBinding(
                ContentPresenter.ContentTemplateProperty,
                new Binding("ContentTemplate") { BindsDirectlyToSource = true, Source = this });
            ContentPresenter.SetBinding(
                ContentPresenter.ContentProperty,
                new Binding("Content") { BindsDirectlyToSource = true, Source = this });

            contentPanel.Children.Add(ContentPresenter);
            contentPanel.Visibility = Visibility.Visible; // ? is this one needed ?
        }

        private void ClearContentVisualTree()
        {
            Debug("ClearContentVisualTree");
            if (ContentPresenter != null)
            {
                //_contentPresenter.SetBinding(ContentPresenter.ContentTemplateProperty, null);
                //_contentPresenter.SetBinding(ContentPresenter.ContentTemplateProperty, null);
                
                ContentPresenter.Content = null;
                ContentPresenter.ContentTemplate = null;

                ContentPresenter.Loaded -= OnContentPresenterLoaded;
                ContentPresenter.Unloaded -= OnContentPresenterUnloaded;

                ContentPresenter = null;
                Debug("    also cleared the presenter.");
            }

            contentPanel.Children.Clear();

            hasContentLoaded = false;
        }

        private void OnContentPresenterUnloaded(object sender, RoutedEventArgs e)
        {
            hasContentLoaded = false;

            OnContentPresenterUnloaded(e);
        }

        private void OnContentPresenterLoaded(object sender, RoutedEventArgs e)
        {
            hasContentLoaded = true;

            OnContentPresenterLoaded(e);
        }

        protected virtual void OnContentPresenterUnloaded(RoutedEventArgs e)
        {
            var handler = ContentPresenterUnloaded;
            if (handler != null)
            {
                handler(this, e);
            }
        }

        protected virtual void OnContentPresenterLoaded(RoutedEventArgs e)
        {
            var handler = ContentPresenterLoaded;
            if (handler != null)
            {
                handler(this, e);
            }
        }

        private void OnCoveringStateChanged(object sender, VisualStateChangedEventArgs e)
        {
            Debug("OnCoveringStateChanged");

            if (e.NewState != null && e.NewState.Name == CoveredStateName && contentPanel != null && ReleaseContentTree)
            {
                ClearContentVisualTree();
            }
            else if (e.NewState != null && e.NewState.Name == UncoveredStateName && ContentPresenter != null && ContentPresenter.IsHitTestVisible == false)
            {
                ContentPresenter.IsHitTestVisible = true;
            }
        }

        [Conditional("DEBUG")]
        private void Debug(string s)
        {
#if DEBUG_CCC
            System.Diagnostics.Debug.WriteLine(s);
#endif
        }
    }
}
